#ifndef SHIJU_SNIFFER_MANAGER_H_INCLUDE
#define SHIJU_SNIFFER_MANAGER_H_INCLUDE

#include <vector>
#include <map>
#include <list>
#include "eutranManager.h"
#include "NmmToX86Protocol.h"
#include "OamMessageProtocol.h"
#include "BbuManager.h"
#include "AutoSnifferCtrl.h"

#define SnifferMgrPtr (SnifferMgr::instance())

enum SnifferResultReportStrategy
{
    RPT_ALL = 0,
    RPT_EXCLUDE_ONLY_IN_RSSI_MEAS = 1
};

enum SnifferTriggerType
{
    OAM_SNF_TRIGGER = 0,
    AUTO_SNF_TRIGGER = 1,
    INVALID_SNF_TRIGGER
};

class SnifferProcedure
{
public:
    
    ~SnifferProcedure();

    bool startSniffer();
    bool processSnifferResult(NmmToX86Protocol_SnifferResultReport& report);
    bool processResultEnd(NmmToX86Protocol_SnifferResultReportEnd& endRpt);
    bool processSnifferStartRsp(NmmToX86Protocol_SnifferStartRsp& rsp);
    bool processSnifferStopRsp(NmmToX86Protocol_SnifferStopRsp& rsp);
    bool stopSniffer();
    void stopProcedure();

    bool isActive();
    bool isPrepare();
    void prepare();

    void waitForBbuConn();
    void stopBbuConnTimer();
    
private:
    friend class SnifferMgr;

    SnifferProcedure(BbuCtrl* bbu);
    
    BbuCtrl* bbuPtr_;
    std::vector<EarfcnRangeType> arfcnRange_;
    std::vector<uint16_t> pciList_;
    bool isPrepareing_;
    bool isActive_;
    uint32_t sentSeqNo_;

    uint32_t waitBbuConnTimer_; 
    EutranTimerElement<SnifferProcedure> waitBbuConnHandler_;
    void bbuConnTimeout();

    SnifferTriggerType snfTrigger_;
};

class SnfPrepareProcedure
{
public:
    SnfPrepareProcedure();

    bool start(uint8_t slotId);
    bool stop();
    bool isProcedureDone();
    bool isActive();
    bool processTxPwerDbRsp(BbuCtrl&, OamMessageProtocol_TxPowerDbmConfigRsp& rsp);
    bool processBbuStateRsp(BbuCtrl&, OamMessageProtocol_SysStatusRsp& rsp);
    void indicateBbuDeactive(BbuCtrl&);
    uint32_t getSnfBbuId();

private:
    SnfPrepareProcedure(const SnfPrepareProcedure&);
    SnfPrepareProcedure& operator=(const SnfPrepareProcedure&);

    bool isActive_;
    std::set<uint32_t> slotIdToBeHandle_;
    uint8_t snfBbuId_;
};

class SnifferMgr
{
public:
    static SnifferMgr* instance();

    bool initialize();

    bool startSniffer(SnifferTriggerType trgType, uint8_t slotId, const std::vector<EarfcnRangeType>& range, const std::vector<uint16_t>* pciList=NULL);
    
    bool stopSniffer();
    bool resetSniffer();

    SnifferMgr* setRssiThreshold(uint16_t rssi);
    uint16_t getRssiThreshold();

    SnifferMgr* setAutoCfgCellFlag(bool autoCfg);
    bool getAutoCfgCellFlag();

    SnifferMgr* setSnifferReportStrategy(SnifferResultReportStrategy rptStrategy);
    uint8_t getSnifferReportStrategy();

    bool isSniffering(uint8_t slotId = 0);
    bool requestBbuSnifferStatus(uint8_t slotId);

    void addResults(uint8_t slotId, std::vector<NmmResult>& results);

    //void getSnifferResult(std::vector<NmmResult>& results);
    //bool getBbuSnifferResult(std::vector<NmmResult>& results, uint8_t slotId);

    void handleNmmMessage(TlvMessage& msg, BbuCtrl& bbu);

    SnifferMgr* procedureTrigByOam(bool);
    void packSnifferResult(BbuCtrl&, uint8_t* buffer, uint32_t& length);
    void packSnifferResult(uint8_t slotId, uint8_t* buffer, uint32_t& length);
    void indicateBbuDeactive(BbuCtrl&);
    void indicateBbuActive(BbuCtrl&);

    bool processTxPwerDbRsp(BbuCtrl&, OamMessageProtocol_TxPowerDbmConfigRsp& rsp);
    bool processBbuStateRsp(BbuCtrl&, OamMessageProtocol_SysStatusRsp& rsp);
    void openTxPwer();

    bool delAutoSnfCfg(uint8_t slotId);
    bool startAutoSnf(uint8_t slotId, uint16_t rssi, std::vector<EarfcnRangeType>& range, uint16_t day, uint8_t hour, uint8_t min);

	bool startSnfWithoutPrepareProc(uint8_t snifferType, uint8_t slotId, const std::vector<EarfcnRangeType>& range);

private:
    friend class SnfPrepareProcedure;
    friend class EutranMgr;
    
    SnifferMgr();
    SnifferMgr(const SnifferMgr&);
    SnifferMgr& operator=(const SnifferMgr&);

    bool startSnf(uint8_t slotId);
    bool startSnifferToDiffBbs(const std::vector<EarfcnRangeType>& range, const std::vector<uint16_t>* pciList=NULL);

    uint32_t calNumOfArfcn(const std::vector<EarfcnRangeType>& range);
    uint32_t calNumOfArfcn(const EarfcnRangeType& range);
    bool calNumOfArfcnPerRange(const std::vector<EarfcnRangeType>& range, std::vector<uint32_t>& num);
    //void recvAllSnifferResults();
    NmmResult* findStrongestRssi(std::vector<NmmResult>&);
    NmmResult* findStrongestRssi(std::vector<NmmResult>&, std::set<uint8_t>& bandSpec);
    std::vector<NmmResult> findHPriority(std::vector<NmmResult>&, std::set<uint8_t>& bandSpec);
    void generateIntraFreqNbrList(BbuCtrl& bbu, uint16_t earfcn, std::vector<uint16_t>& intraFreqNbrPciList);
    void generateInterFreqNbrList(BbuCtrl& bbu, uint16_t earfcn, std::vector<uint16_t>& interFreqList);

    void configCellToBbu(BbuCtrl& bbu);
    void processNmmStatusResponse(NmmToX86Protocol_NmmStatusRpt& rpt);

    void handleSnfResult(BbuCtrl&);

    SnifferResultReportStrategy rptStrategy_;
    bool isAutoCfgCell_;

    SnifferProcedure* procedures_[BbuManager::MAX_BBU_INSTANCES];
    std::vector<NmmResult> snifferResults_[BbuManager::MAX_BBU_INSTANCES];
    AutoSnifferCtrl* autoSnfCtrls_[BbuManager::MAX_BBU_INSTANCES];

    bool isCurrentProcTrigByOam_;

    SnfPrepareProcedure prepareProc_;
};

#endif
